<?php

namespace common\components\paymch;

use Yii;

/**
 * 在线支付服务端
 *
 * @author emhome<emhome@163.com>
 * @since 2.0
 */
class MchServer extends \yii\base\Component {

    //应用ID
    public $appId;
    //私钥文件路径，优先使用文件私钥
    public $rsaPublicKeyFilePath;
    //使用读取字符串格式
    public $rsaPublicKey;
    //返回数据格式
    public $format = "json";
    //api版本
    public $version = "1.0";
    //提交字符集编码
    public $charset = "UTF-8";
    //使用文件读取文件格式，请只传递该值
    public $publicKey = null;
    //签名类型
    public $signType = "RSA2";
    //
    private $fileCharset = "UTF-8";

    /**
     * 验证签名
     * 在使用本方法前，必须初始化AopClient且传入公钥参数。
     * 公钥是否是读取字符串还是读取文件，是根据初始化传入的值判断的。
     */
    public function checkSignature($params, $signType = 'RSA2') {
        $sign = $params['sign'];
        $params['sign_type'] = null;
        $params['sign'] = null;
        $data = $this->getSignContent($params);
        return $this->verify($data, $sign, $signType);
    }

    /**
     * 获取签名内容
     */
    public function getSignContent($params) {
        ksort($params);
        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === MchUtils::checkEmpty($v) && "@" != substr($v, 0, 1)) {
                //转换成目标字符集
                $v = MchUtils::characet($v, $this->charset, $this->fileCharset);
                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }
        unset($k, $v);
        return $stringToBeSigned;
    }

    /**
     * 校验签名
     */
    private function verify($data, $sign, $signType = 'RSA2') {
        $res = MchUtils::getPublicKey($this->rsaPublicKeyFilePath, $this->rsaPublicKey);
        if (!$res) {
            die('支付中心RSA公钥错误。请检查公钥文件格式是否正确');
        }
        //调用openssl内置方法验签，返回bool值
        if ($signType == "RSA2") {
            $result = (bool) openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
        } else {
            $result = (bool) openssl_verify($data, base64_decode($sign), $res);
        }
        if (!MchUtils::checkEmpty($this->rsaPublicKeyFilePath)) {
            //如使用的是文件证书，释放资源
            openssl_free_key($res);
        }
        return $result;
    }

}
